package org.common.plugin;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.Resource;

/**
 *
 * @author gus
 */
public class PluginRegistry
{
    private Resource pluginConfigFile;
    private final Map<String, PluginInfo> storage = new HashMap<String, PluginInfo>();

    public void setPluginConfigFile(Resource pluginConfigFile)
    {
        this.pluginConfigFile = pluginConfigFile;
    }

    private void parseConfigFile() throws Exception
    {
        storage.clear();
        InputStream stream = pluginConfigFile.getInputStream();
        try
        {
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            Element root = document.getRootElement();
            parseSection(root, "//plugin", storage, false);
            parseSection(root, "//typeModule", storage, true);
        }
        catch (Exception exc)
        {
            Logger.getLogger(PluginRegistry.class.getName()).severe(exc.getMessage());
        }
        finally
        {
            stream.close();
        }
    }

    public PluginInfo getPluginInfo(String name) throws Exception
    {
        checkStorage();
        return storage.get(name);
    }

    public PluginInfo[] getPluginInfos() throws Exception
    {
        checkStorage();
        return new ArrayList<PluginInfo>(storage.values()).toArray(new PluginInfo[0]);
    }

    private void checkStorage() throws Exception
    {
        if (storage.isEmpty())
        {
            parseConfigFile();
        }
    }

    private PluginInfo makePluginInfo(Element node) throws Exception
    {
        PluginInfo info = new PluginInfo();
        info.setName(node.attributeValue("name"));
        info.setClassName(node.attributeValue("class"));

        UUID uid = UUID.fromString(node.selectSingleNode(".//uuid").getText());
        info.setGuid(uid);

        String path = node.selectSingleNode(".//filePath").getText();
        File filePath = combinePath(path);
        info.setFilePath(filePath);
        return info;
    }

    private File combinePath(String filePath) throws IOException
    {
        File pluginDir = pluginConfigFile.createRelative(filePath).getFile();
        return pluginDir.getCanonicalFile();

    }

    private void parseSection(Element root, String xpathExpression, Map<String, PluginInfo> hash, boolean isPlugin) throws Exception
    {
        List<Element> plugins = root.selectNodes(xpathExpression);
        for (Element element : plugins)
        {
            PluginInfo info = makePluginInfo(element);
            info.setModule(isPlugin);
            hash.put(info.getName(), info);
        }
    }
}
